﻿using Future.Shared.Core.Filters;
using Futuret.Core.DependencyInjection.Extensions;
using Futuret.Core.Futuret;
using Futuret.Core.Futuret.Interface;
using Futuret.Repositor.Db;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Future.Shared.Core.Registrar;

/// <summary>
///     Author: Riva
///     Date: 2023/7/11 14:10
///     Description:抽象WebApi注入器
/// </summary>
public abstract partial class AbstractApiDependencyRegistrar : IDependencyRegistrar
{
    /// <summary>
    ///     构造函数
    /// </summary>
    /// <param name="service"></param>
    protected AbstractApiDependencyRegistrar(IServiceCollection service)
    {
        Services = service;
        Configuration = service.GetConfiguration();
        ServiceInfo = service.GetServiceInfo();
    }

    /// <summary>
    ///     IConfiguration
    /// </summary>
    protected IConfiguration Configuration { get; init; }

    /// <summary>
    ///     IServiceCollection
    /// </summary>
    protected IServiceCollection Services { get; init; }

    /// <summary>
    ///     IServiceInfo
    /// </summary>
    protected IAppInfo ServiceInfo { get; init; }

    /// <summary>
    ///     注册器名称
    /// </summary>
    public string Name => "Future.Api";

    /// <summary>
    ///     新增服务
    /// </summary>
    public abstract void AddService();

    /// <summary>
    ///     注册Webapi通用的服务
    /// </summary>
    protected virtual void AddWebApiDefault()
    {
        //ico 配置最先加载
        AddConfigure();
        
        Services
            .AddHttpContextAccessor()
            .AddMemoryCache()
            .AddEndpointsApiExplorer()
            .AddDependencyInjection();

        AddControllers();
        AddSwaggerGen();
        AddDb();
        AddCors();
    }
    
    /// <summary>
    ///     配置数据库相关 redis sqlsugar
    /// </summary>
    protected virtual void AddDb()
    {
        //遍历配置
        DbContext.DbConfigs.ForEach(it =>
        {
            //是否需要初始化数据库
            if (it.IsInitDb) DbContext.InitDb(it); //初始化数据库表结构
        });
    }
    

    /// <summary>
    ///     Controllers相关注入
    /// </summary>
    protected virtual void AddControllers()
    {
        Services
            .AddControllers(options =>
            {
                options.ModelValidatorProviders.Clear(); //去除微软自带的参数验证
                //过滤器
                options.Filters.Add(typeof(CustomExceptionFilterAttribute));
            })
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver =
                    new CamelCasePropertyNamesContractResolver(); // 首字母小写（驼峰样式）
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // 时间格式化
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; //忽略空值 不包含属性的null序列化
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 忽略循环引用
            });
    }

    /// <summary>
    ///     注册跨域组件
    /// </summary>
    protected virtual void AddCors()
    {
        Services.AddCors(c =>
        {
            //TODO 可扩展跨域限制
            //允许任意跨域请求
            c.AddPolicy("cors", policy =>
            {
                policy.SetIsOriginAllowed(host => true)
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials();
            });
        });
    }

    /// <summary>
    ///     注册swagger组件
    /// </summary>
    protected virtual void AddSwaggerGen()
    {
        Services.AddSwaggerGen(options =>
        {
            options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
            {
                Description = "请输入带有Bearer的Token，形如 “Bearer {Token}” ",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            });
            options.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
                    },
                    new[] { "readAccess", "writeAccess" }
                }
            });
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "Future.Api", Version = "v1" });
            foreach (var assembly in AppInfo.GetInstance().AllAssemblies)
            {
                var file = Path.Combine(AppContext.BaseDirectory, $"{assembly.GetName().Name}.xml");
                if (!File.Exists(file))
                    continue;
                options.IncludeXmlComments(file, true);
                options.OrderActionsBy(x => x.RelativePath);
            }
        });
    }
}